#include "limage.h"
#include <QImage>
#include <QRgb>
#include <QColor>
#include "math.h"
#include <QString>
LImage::LImage()
{
}
LImage::LImage(QImage qImage)

{
    if(this->image.isGrayscale())
    {
        this->historgram = new HistogramGray(&qImage);
    }
    else
    {
        this->historgram= new HistogramRGB(&qImage) ;


    }

    historgram->calcHistogram();

}

LImage::LImage(int width,int height,QImage::Format format):image(width,height,format)
{
   /* QImage tempImage(width,height,this->image.format());
    this->image=QImage::QImage(width,height,format);
    this->historgram= HistogramGray::HistogramGray(image);
    cout<<"Hehhhhhhhhhh"<<this->image.width()<<endl;*/
    if(this->image.isGrayscale())
    {
        this->historgram = new HistogramGray(&image);
    }
    else
    {
        this->historgram= new HistogramRGB(&image) ;
    }
    historgram->calcHistogram();
}

LImage::LImage(QString fileName):image(fileName,NULL)
{
    if(this->image.isGrayscale())
    {
        this->historgram = new HistogramGray(&image);
    }
    else
    {
        this->historgram= new HistogramRGB(&image) ;
    }

    //QImage image(fileName,NULL);
    //this->image=image;
    //this->historgram= HistogramGray::HistogramGray(image);
    historgram->calcHistogram();
}
LImage::LImage(QString path, char format)
{
     if(format!=4)
    {
  char * ptr;
  ptr=(char*)&format;


        QImage tempImage(path,NULL);
        QImage convertedImage=  tempImage.convertToFormat(QImage::Format_ARGB32 );
        this->image=convertedImage;
        QString temp = "temp.jpg";
        const char h=4;
        convertedImage.save(temp,NULL);

    }


}

QImage LImage::getImage()
{
    return this->image;
}
void LImage::loadLimage(QString path)

{
     this->image.load(path,NULL);
}
QRgb LImage::pixel(int i,int j )
{
    return (this->image.pixel(i,j));
}

void LImage::setPixel(int i,int j,int red,int green,int blue)
{
    QColor color= QColor ::fromRgb(red,green,blue,255);
    QRgb formedRgb=color.rgb();
    this->image.setPixel(i,j,formedRgb);
}
void LImage::setPixel(int i,int j,double red,double green,double blue)
{
    int redInt,blueInt,greenInt;
    redInt = floor(red);
    blueInt= floor(blue);
    greenInt=floor(green);

    QColor color= QColor ::fromRgb(redInt,greenInt,blueInt,255);
    QRgb formedRgb=color.rgb();
    this->image.setPixel(i,j,formedRgb);
}


LImage LImage ::convertToGrayScale()
{
    QRgb tempRgb,formedRgb;
    QColor color,grayColor;
    double resultValue ;
    int redTemp,greenTemp,blueTemp;

    LImage returnedImage(this->image.width(),this->image.height(),this->image.format());
    cout <<"this is the values "<<this->image.width()<<endl;
    int index ;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            //index = this->image.pixelIndex(i,j);
            tempRgb= this->pixel(i,j);
            color = QColor::fromRgb(tempRgb);
            redTemp= color.red();
            greenTemp=color.green();
            blueTemp= color.blue();
            resultValue= 0.3*redTemp+0.59*greenTemp+0.11*blueTemp;
            returnedImage.setPixel(i,j,resultValue,resultValue,resultValue);

        }
    }
    return returnedImage;
}
LImage LImage ::convertToNegative()
{
    cout <<"The Image Format is "<<this->image.format()<<endl;

    if(this->image.format()!=4)
    {
         this->image= this->image.convertToFormat(QImage::Format_ARGB32,Qt::AutoColor);
         QString temporary("TemporarySavedImage.jpg");
         this->image.save(temporary,NULL);
     }
    QRgb tempRgb,formedRgb;
    QColor tempColor,formedColor;
    int tempComponent;
    LImage returnedImage(this->image.width(),this->image.height(),this->image.format());

    if(this->image.isGrayscale()==false)
    {
        cout<<"The Image Is not GrayScale"<<endl;
    }
    else
    {
        for(int i=0;i<this->image.width();i++)
        {
            for(int j=0;j<this->image.height();j++)
            {
                tempRgb = this->pixel(i,j);
                tempColor= QColor::fromRgb(tempRgb);
                tempComponent= tempColor.red();
                tempComponent= 256-1-tempComponent;
                returnedImage.setPixel(i,j,tempComponent,tempComponent,tempComponent);
            }

         }

           }
     return returnedImage ;

}
LImage LImage::normalizeImage()
{
    LImage returnedImage(this->image.width(),this->image.height(),this->image.format());

    QRgb tempRgb,formedRgb;
    QColor color,formedColor;
    int component;

    int max=0;
    double fraction;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
          QRgb rgb= this->image.pixel(i,j);
           QColor color=(rgb);
           if(max<color.red())
               max=color.red();
        }



    }
    cout<<"Max is "<<max<<endl;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            tempRgb= this->image.pixel(i,j);
            color=QColor::fromRgb(tempRgb);
            component= color.red();
            fraction= component/max;
            component= floor(255*fraction);
            returnedImage.setPixel(i,j,component,component,component);


        }



    }

    return returnedImage;
}


LImage LImage:: mergeGrayImage(double factor1, LImage secondImage,double  factor2)
{
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());

    QRgb firstRgb,secondRgb,formedRgb;
    QColor firstColor,secondColor,formedColor;

    if((this->image.width()!=secondImage.image.width())||this->image.height()!=secondImage.image.height())
    {
        cout<<"The Two Images Cannot Be Merged Because They Do not Have the Same Dimenesions"<<endl;
        return secondImage;
    }

    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            double firstComponent,secondComponent,resultComponent;
            firstRgb= this->pixel(i,j);
            firstColor=QColor::fromRgb(firstRgb);
            firstComponent= firstColor.red();

            secondRgb= secondImage.image.pixel(i,j);
            secondColor=QColor::fromRgb(secondRgb);
            secondComponent= secondColor.red();
            resultComponent=factor1*firstComponent+factor2*secondComponent;
            outputImage.setPixel(i,j,resultComponent,resultComponent,resultComponent);


        }
        }
    return outputImage;


}
LImage LImage:: mergeColorImage(double factor1, LImage secondImage,double  factor2)
{
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());
    QRgb firstRgb,secondRgb,formedRgb;
    QColor firstColor,secondColor,formedColor;

    if((this->image.width()!=secondImage.image.width())||this->image.height()!=secondImage.image.height())
    {
        cout<<"The Two Images Cannot Be Merged Because They Do not Have the Same Dimenesions"<<endl;
        return secondImage;
    }

    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            double firstRed,secondRed,resultRed;
            double firstBlue,secondBlue,resultBlue;
            double firstGreen,secondGreen,resultGreen;
            firstRgb= this->pixel(i,j);
            firstColor=QColor::fromRgb(firstRgb);
            firstRed= firstColor.red();
            firstGreen= firstColor.green();
            firstBlue= firstColor.blue();


            secondRgb= secondImage.image.pixel(i,j);
            secondColor=QColor::fromRgb(secondRgb);
            secondRed= secondColor.red();
            secondGreen= secondColor.green();
            secondBlue= secondColor.blue();

            resultRed=factor1*firstRed+factor2*secondRed;
            resultGreen=factor1*firstGreen+factor2*secondGreen;
            resultBlue=factor1*firstBlue+factor2*secondBlue;
            outputImage.setPixel(i,j,resultRed,resultGreen,resultBlue);
        }
        }
    return outputImage;


}
LImage LImage::mergeImage(double factor1,LImage secondImage,double factor2)
{
    LImage outputImage;
    if((this->image.isGrayscale()==true)&&(secondImage.image.isGrayscale()==true))
    {
        outputImage =this->mergeGrayImage(factor1,secondImage,factor2);
        return outputImage;
    }
    else
        if((this->image.isGrayscale()==false)&&(secondImage.image.isGrayscale()==true))
        {

            //this= this->convertToGrayScale();
           //return  this->mergeGrayImage(factor1,secondImage,factor2);
        return this->mergeColorImage(factor1,secondImage,factor2);

        }
    else
        if((this->image.isGrayscale()==true)&&(secondImage.image.isGrayscale()==false))
        {
            //secondImage=secondImage.convertToGrayScale();
            //return this->mergeGrayImage(factor1,secondImage,factor2);
            return this->mergeColorImage(factor1,secondImage,factor2);
        }
    else
        cout<<"Heey I am There";
        return mergeColorImage(factor1,secondImage,factor2);

}
void LImage ::saveImage(QString filePath)
{
    this->image.save(filePath,NULL);
}
LImage LImage ::grayHistogramEqualization()
{
    unsigned long* CDF;
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());
    this->historgram->calcHistogram();
    this->historgram->calcCDF();
    HistogramGray* histogramGray=(HistogramGray*)(historgram);
     CDF= histogramGray->getCDF();
            double max =CDF[255];

    double factor = 255/max;
   QColor retrivedColor;
   QRgb retrivedRgb;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            double formedComponent;

            retrivedRgb= this->pixel(i,j);
            retrivedColor= QColor::fromRgb(retrivedRgb);
            formedComponent= CDF[retrivedColor.red()]*factor ;
            outputImage.setPixel(i,j,formedComponent,formedComponent,formedComponent);


        }
        }
    return outputImage;

}
LImage LImage ::RGBhistogramEqulization()
{
    unsigned long* redCDF;
    unsigned long* greenCDF;
    unsigned long* blueCDF;
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());
    this->historgram->calcHistogram();
    this->historgram->calcCDF();
    HistogramRGB* RGBhisto= (HistogramRGB*) (this->historgram);
    redCDF=RGBhisto->getRedCDF();
    double maxRed =redCDF[255];
    double redFactor = 255/maxRed;
    greenCDF= RGBhisto->getGreenCDF();
    blueCDF=RGBhisto->getBlueCDF();
    double maxBlue,maxGreen;
    double greenFactor,blueFactor;
    maxGreen= greenCDF[255];
    maxBlue=blueCDF[255];
    greenFactor= 255/maxGreen;
    blueFactor= 255/maxBlue;
   QColor retrivedColor;
   QRgb retrivedRgb;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            double formedRed,formedGreen,formedBlue;

            retrivedRgb= this->pixel(i,j);
            retrivedColor= QColor::fromRgb(retrivedRgb);
           // formedComponent= CDF[retrivedColor.red()]*factor ;

            formedRed= redCDF[retrivedColor.red()]*redFactor;
            formedGreen= greenCDF[retrivedColor.green()]*greenFactor;
            formedBlue= blueCDF[retrivedColor.blue()]*blueFactor;
            outputImage.setPixel(i,j,formedRed,formedGreen,formedBlue);


        }
        }
    return outputImage;

}

/*LImage LImage ::HSIHistogramEqualization()
{
    QRgb retrivedRGB;
    QColor retrivedColor,HSIColor;
    double

    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            double formedRed,formedGreen,formedBlue;

            retrivedRgb= this->pixel(i,j);

            retrivedColor= QColor::fromRgb(retrivedRgb);
           HSIColor= retrivedColor.toHsl();
           // formedComponent= CDF[retrivedColor.red()]*factor ;
            if(retrivedColor.blue()<0)
            {
                cout<<"hi";
            }
            formedRed= redCDF[retrivedColor.red()]*redFactor;
            formedGreen= greenCDF[retrivedColor.green()]*greenFactor;
            formedBlue= blueCDF[retrivedColor.blue()]*blueFactor;
            outputImage.setPixel(i,j,formedRed,formedGreen,formedBlue);


        }
        }
}*/
LImage LImage::HSIHistogramEqualization()
{
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());
    unsigned long * intensityCDF;
    double maxIntensity;
    this->historgram = new HistogramHSI(&this->image);
    this->historgram->calcHistogram();
    this->historgram->calcCDF();
    HistogramHSI* historgram= (HistogramHSI*)this->historgram;
    intensityCDF= historgram->getIntensityCDF();
    maxIntensity = intensityCDF[255];
    double factor= 255/maxIntensity;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
            QRgb tempRgb = this->pixel(i,j);
            QColor tempColor= QColor::fromRgb(tempRgb);
            double formedIntensity;
            QColor HSIColor = tempColor.toHsl();
            formedIntensity= intensityCDF[HSIColor.value()]*factor;
            int intIntisity = floor(formedIntensity);
            QColor formedColor= QColor ::fromHsv(HSIColor.hsvHue(),HSIColor.hsvSaturation(),intIntisity,255);


            outputImage.setPixel(i,j,formedColor.red(),formedColor.green(),formedColor.blue());


        }
    }
    this->historgram = new HistogramRGB(&this->image);
    return outputImage;
}

LImage LImage::histogramEqulization()
{
    if(this->image.isGrayscale())
    {
        return this->grayHistogramEqualization();
    }
    else
        if(this->image.isGrayscale()==false)
    {
        return this->RGBhistogramEqulization();
    }
}
LImage LImage::convertToColorNegative()
{
            QRgb tempRgb,formedRgb;
        QColor tempColor,formedColor;
        int tempred,tempBlue,tempGreen;
        LImage returnedImage(this->image.width(),this->image.height(),this->image.format());
        if(this->image.isGrayscale()==true)
        {
            cout<<"The Image Is GrayScale"<<endl;
        }
        else
        {
            for(int i=0;i<this->image.width();i++)
            {
                for(int j=0;j<this->image.height();j++)
                {
                    tempRgb = this->pixel(i,j);
                    tempColor= QColor::fromRgb(tempRgb);
                    tempred= tempColor.red();
                    tempGreen =tempColor.green();
                    tempBlue= tempColor.blue();
                    tempred= 256-1-tempred;
                    tempGreen= 256-1-tempGreen;
                    tempBlue=256-1-tempBlue;
                    if((tempred<0)||(tempGreen<0)||(tempBlue<0))
                        cout<<"ALO";
                    returnedImage.setPixel(i,j,tempred,tempGreen,tempBlue);
                }

             }

               }
         return returnedImage ;

    }
LImage LImage ::grayHistogramStretching()
{
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());
    int max,min,tempComponent;
    double formedComponent ;
    double doubleTempComponent;
    QColor tempColor;
    max =0;
    min= 256;
    QRgb tempRGB;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
          tempRGB = this->pixel(i,j);
          tempColor= QColor::fromRgb(tempRGB);
          tempComponent= tempColor.red();
          if(tempComponent>max)
          {
              max=tempComponent;
          }
          if(tempComponent<min)
          {
              min= tempComponent;
          }
        }

    }
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
          tempRGB = this->pixel(i,j);
          tempColor= QColor::fromRgb(tempRGB);
          tempComponent= tempColor.red();
          double factor= 255/(double)(max-min);
          doubleTempComponent= tempComponent;
          doubleTempComponent= (doubleTempComponent-min)*factor;
          outputImage.setPixel(i,j,doubleTempComponent,doubleTempComponent,doubleTempComponent);
        }

    }
    return outputImage;


}
LImage LImage ::colorHSIHistogramStretching()
{
    LImage outputImage(this->image.width(),this->image.height(),this->image.format());
    int max,min,tempValue;
    double formedComponent ;
    double doubleTempValue;
    QColor tempColor;
    max =0;
    min= 256;
    QRgb tempRGB;
    int formedValue;
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
          tempRGB = this->pixel(i,j);
          tempColor= QColor::fromRgb(tempRGB);
          tempValue= tempColor.value();
          if(tempValue>max)
          {
              max=tempValue;
          }
          if(tempValue<min)
          {
              min= tempValue;
          }
        }

    }
    for(int i=0;i<this->image.width();i++)
    {
        for(int j=0;j<this->image.height();j++)
        {
          tempRGB = this->pixel(i,j);
          tempColor= QColor::fromRgb(tempRGB);
          tempValue= tempColor.value();
          double factor= 255/(double)(max-min);
          doubleTempValue= tempValue;
          doubleTempValue = (doubleTempValue-min)*factor;
          formedValue= (int)doubleTempValue;
          QColor formedColor = QColor ::fromHsv(tempColor.hsvHue(),tempColor.hsvSaturation(),formedValue);
          outputImage.setPixel(i,j,formedColor.red(),formedColor.green(),formedColor.blue());
        }

    }
    return outputImage;


}
LImage LImage::intelligentScissors()
{

}





